package com.benshou.bcss.common.jackson;

import com.benshou.bcss.common.rest.RequestHeaderContext;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.jackson.JsonComponent;

import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Optional;

import static java.time.temporal.ChronoField.*;

/**
 * Json序列化器，用于处理 {@link ZonedDateTime}
 *
 * @author <a href="mailto:liuzhenbang@benshou.com">Liu Zhenbang</a>
 */
@JsonComponent
public class ZonedDateTimeSerializer extends JsonSerializer<ZonedDateTime> implements ContextualSerializer {

    /**
     * 默认时间格式化对象
     */
    private static final DateTimeFormatter DEFAULT_FORMATTER = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral(' ')
            .appendValue(HOUR_OF_DAY, 2)
            .appendLiteral(':')
            .appendValue(MINUTE_OF_HOUR, 2)
            .appendLiteral(':')
            .appendValue(SECOND_OF_MINUTE, 2)
            .toFormatter();

    /**
     * 时间格式化对象
     */
    @NotNull
    private DateTimeFormatter formatter = DEFAULT_FORMATTER;

    @Override
    public void serialize(ZonedDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value == null) {
            gen.writeNull();
        } else {
            var timezone = RequestHeaderContext.getTimezoneDefaultSystem();
            // 一般来说，都是使用默认时区，不需要重新偏移计算
            gen.writeString(this.formatter.format(value.withZoneSameInstant(timezone)));
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
        return Optional.ofNullable(property)
                // 提取 pattern 用以输出
                .map(it -> it.getAnnotation(JsonFormat.class))
                .map(format -> {
                    var pattern = format.pattern();
                    return pattern == null || pattern.isBlank() ? null: pattern;})
                .map(pattern -> {
                    var serializer = new ZonedDateTimeSerializer();
                    serializer.formatter = DateTimeFormatter.ofPattern(pattern);
                    return serializer;})
                .orElse(this);
    }
}
